/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.agi.ia.kohonen;

import br.com.agi.ia.kohonen.Camada;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author renatogrosz
 */
public class CamadaThread extends Camada {
    protected Quadrado qa,qb,qc,qd;
    public CamadaThread(TamanhoCamada tamanho,InicializadorDados inicializador){
        super(tamanho,inicializador);
        
        int xmeio;
        int ymeio;        
        int xx;
        int yy;
        
        xx=tamanho.getCamada().x;
        yy=tamanho.getCamada().y;
        
        
        xmeio=tamanho.getCamada().x/2;
        ymeio=tamanho.getCamada().y/2;
        
        qa=new Quadrado(0,0,xmeio,ymeio);
        qb=new Quadrado(xmeio,0,xx,ymeio);
        qc=new Quadrado(0,ymeio,xmeio,yy);
        qd=new Quadrado(xmeio,ymeio,xx,yy);
        
    }
    
    
    @Override
     public void calcularEntrada(double[][] entrada){
         Thread ta,tb,tc,td;
         
         ta=new CalculadorEntrada(camada, qa, entrada);
         tb=new CalculadorEntrada(camada, qb, entrada);
         tc=new CalculadorEntrada(camada, qc, entrada);
         td=new CalculadorEntrada(camada, qd, entrada);
         
         ta.start();
         tb.start();
         tc.start();
         td.start();
         
        try {
            ta.join();
            tb.join();
            tc.join();
            td.join();
            
        } catch (InterruptedException ex) {
            throw new RuntimeException(ex);            
        }
    }
    
    @Override
    public void atualizarCamada(double fator){
        Thread ta,tb,tc,td;
        ta=new AtualizadorCamada(camada,qa,fator);
        tb=new AtualizadorCamada(camada,qb,fator);
        tc=new AtualizadorCamada(camada,qc,fator);
        td=new AtualizadorCamada(camada,qd,fator);
        
        ta.start();
        tb.start();
        tc.start();
        td.start();
        
        try {
            ta.join();
            tb.join();
            tc.join();
            td.join();
            
        } catch (InterruptedException ex) {
            throw new RuntimeException(ex);            
        }
        
    }
    
    private class AtualizadorCamada extends Thread{
        private double fator;
        private Quadrado quadrado;
        private Neuron[][] camada;
        
        public AtualizadorCamada(Neuron[][] camada, Quadrado quadrado, double fator){
            this.fator=fator;
            this.quadrado=quadrado;
            this.camada=camada;
        }
        
        @Override
        public void run(){
            int i;
            int j;
            double d;

            for(i=quadrado.x;i<quadrado.xx;i++){
                double dx;
                dx=vencedor.x-i;
                dx=dx*dx;
                for(j=quadrado.y;j<quadrado.yy;j++){
                    double dy;
                    double f;
                    dy=vencedor.y-j;
                    dy=dy*dy;
                    d=dx+dy;
                    f=1 / ( (d/fator) + 1);
                    camada[i][j].atualizar(f);
                }
            }
        }
    } 

    
   private class CalculadorEntrada extends Thread{
        protected Neuron[][] camada;
        protected Quadrado quadrado;
        protected double[][] entrada;
       
        public CalculadorEntrada(Neuron[][] camada, Quadrado quadrado, double[][] entrada){
           this.camada=camada;
           this.quadrado=quadrado;
           this.entrada=entrada;
        }
       
        @Override
        public void run(){
            int i,j;
            for(i=quadrado.x;i<quadrado.xx;i++){
                for(j=quadrado.y;j<quadrado.yy;j++){
                    camada[i][j].calcularEntrada(entrada);                
                }
            }
        }
   }  
     
    
    
   protected class Quadrado{
       private Tamanho ini, fim;
       int x,y,xx,yy;
       
       
       public Quadrado(int x,int y, int xx, int yy){
           ini=new Tamanho(x,y);
           fim=new Tamanho(xx,yy);
           
           this.x=x;
           this.y=y;
           this.xx=xx;
           this.yy=yy;
       }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 97 * hash + (this.ini != null ? this.ini.hashCode() : 0);
            hash = 97 * hash + (this.fim != null ? this.fim.hashCode() : 0);
            return hash;
        }
       
        @Override
       public boolean equals(Object o){
           boolean retorno;
           retorno=false;
           if(o instanceof Quadrado){
               Quadrado outro;
               outro=(Quadrado) o;
               if(outro.ini.equals(ini)){
                   retorno=outro.fim.equals(fim);
               }
           }
           return(retorno);
       }
       public Tamanho getIni(){
           return(ini);
       }
       
       
       public Tamanho getFim(){
           return(fim);
       }
   }
     
   
}
